#include <cliopt.h>
#include <i264e_common.h>
#ifdef DMALLOC
#include <imp/dmalloc.h>
#endif
typedef struct
{
	cli_input_t input;
	hnd_t p_handle;
	i264e_pic_t pic;
	i264e_threadpool_t *pool;
	int next_frame;
	int frame_total;
	struct thread_input_arg_t *next_args;
} thread_hnd_t;

typedef struct thread_input_arg_t
{
	thread_hnd_t *h;
	i264e_pic_t *pic;
	int i_frame;
	int status;
	cli_opt_t *opt;
} thread_input_arg_t;

static int open_file(char *psz_filename, cli_opt_t *opt)
{
	thread_hnd_t *h = NULL;
	if ((h = malloc(sizeof(thread_hnd_t))) == NULL) {
		fprintf(stderr, "malloc failed\n");
		goto err_malloc;
	}
	if (opt->cli_input->picture_alloc( &h->pic, opt)) {
		fprintf(stderr, "picture_alloc failed\n");
		goto err_picture_alloc;
	}
	h->input = *(opt->cli_input);
	h->p_handle = (opt->hin);
	h->next_frame = -1;
	h->next_args = malloc( sizeof(thread_input_arg_t) );
	if(!h->next_args)
		return -1;
	h->next_args->h = h;
	h->next_args->status = 0;
	h->next_args->opt = opt;
	h->frame_total = opt->totalframe;
	thread_input.picture_alloc = h->input.picture_alloc;
	thread_input.picture_clean = h->input.picture_clean;

	if( i264e_threadpool_init( &h->pool, 1, NULL, NULL ) )
		return -1;

	opt->hthread = h;
    return 0;

err_picture_alloc:
	free(h);
err_malloc:
	return -1;
}

static void read_frame_thread_int(thread_input_arg_t *i)
{
	i->status = i->h->input.read_frame(i->pic, i->opt);
}

static int read_frame(i264e_pic_t *p_pic, cli_opt_t *opt)
{
	thread_hnd_t *h = opt->hthread;
	int ret = 0;
	int i_frame = opt->i_frame;
	if(h->next_frame >= 0)
	{
		i264e_threadpool_wait(h->pool, h->next_args);
		ret |= h->next_args->status;
	}
	if(h->next_frame == i_frame)
		C_XCHG(i264e_pic_t, *p_pic, h->pic);
	else
	{
		thread_input.release_frame(&h->pic, opt);
		ret |= h->input.read_frame(p_pic, opt);
	}
	if(!h->frame_total || i_frame+1 < h->frame_total)
	{
		h->next_frame =
		h->next_args->i_frame = i_frame+1;
		h->next_args->pic = &h->pic;
		i264e_threadpool_run(h->pool, (void*)read_frame_thread_int, h->next_args);
	}
	else
		h->next_frame = -1;
	return ret;
}

static int release_frame(i264e_pic_t *pic, cli_opt_t *opt)
{
	thread_hnd_t *h = opt->hthread;
	if(h->input.release_frame)
		return h->input.release_frame(pic, opt);
	return 0;
}

static int close_file(cli_opt_t *opt)
{
	thread_hnd_t *h = opt->hthread;
	i264e_threadpool_delete(h->pool);
	h->input.close_file(opt);
	h->input.picture_clean(&(h->pic), opt);
	free(h->next_args);
	free(h);
	return 0;
}

cli_input_t thread_input = { open_file, NULL, read_frame, release_frame, NULL, close_file };
